#include <stdlib.h>

#ifndef IMI_PARSER_AAC
#define IMI_PARSER_AAC 1

#pragma pack(push,1)

#define AAC_ADTS_HEADER (sizeof(aac_adts_fixed_header) + sizeof(aac_adts_variable_header) - 1)

typedef struct _aac_adts_fixed_header
{
	unsigned int _syncword:12;
	unsigned int _id:1;
	unsigned int _layer:2;
	unsigned int _protection_absent:1;
	unsigned int _profile:2;
	unsigned int _sampling_frequency_index:4;
	unsigned int _private_bit:1;
	unsigned int _channel_configuration:3;
	unsigned int _original_copy:1;
	unsigned int _home:1;
}aac_adts_fixed_header;

typedef struct _aac_adts_variable_header
{
	unsigned int _copyright_identification_bit:1;
	unsigned int _copyright_identification_start:1;
	unsigned int _aac_frame_length:13;
	unsigned int _adts_buffer_fullness:11;
	unsigned int _numble_of_raw_data_blocks_in_frame:2;
}aac_adts_variable_header;

inline aac_adts_fixed_header* imi_parser_aac_header_net(unsigned char* aac_data_net)
{
	aac_adts_fixed_header* fixed = (aac_adts_fixed_header*)malloc(sizeof(aac_adts_fixed_header));
	fixed->_syncword = (aac_data_net[0]|(aac_data_net[1]<<4));
	fixed->_id = ((aac_data_net[1]>>3)&0x1);
	fixed->_layer = ((aac_data_net[1]>>1)&0x3);
	fixed->_protection_absent = ((aac_data_net[1])&0x1);
	fixed->_profile = ((aac_data_net[2]>>6)&0x3);
	fixed->_sampling_frequency_index = ((aac_data_net[2]>>2)&0xF);
	fixed->_private_bit = ((aac_data_net[2]>>1)&0x1);
	fixed->_channel_configuration = (((aac_data_net[2]&0x1)<<2)|((aac_data_net[3]>>6)&0x3));
	fixed->_original_copy = ((aac_data_net[3]>>5)&0x1);
	fixed->_home = ((aac_data_net[3]>>4)&0x1);
	return fixed;
}

inline int imi_parser_aac_header_sampling_frequency_index(unsigned int index)
{
	switch (index)
	{
	case 0:
		return 96000;
	case 4:
		return 44100;
	case 5:
		return 32000;
	case 8:
		return 16000;
	case 11:
		return 8000;
	default:
		break;
	}
	return 0;
}

inline int imi_make_aac_header_sampling_frequency_index(unsigned int frequency)
{
	switch (frequency)
	{
	case 96000:
		return 0;
	case 44100:
		return 4;
	case 32000:
		return 5;
	case 16000:
		return 8;
	case 8000:
		return 11;
	default:
		break;
	}
	return -1;
}

inline unsigned char* imi_make_aac_header_net(unsigned int frequency, unsigned int channel ,unsigned int frame_len)
{
	unsigned char* aac_header = (unsigned char*)malloc(AAC_ADTS_HEADER);
	unsigned char* aac_header_buff = aac_header;
	memset(aac_header, 0, AAC_ADTS_HEADER);
	*aac_header_buff++ = 0xff;																	//syncword  (0xfff, high_8bits)  
	*aac_header_buff = 0xf0;																	//syncword  (0xfff, low_4bits)  
	*aac_header_buff |= (1 << 3);																//ID (0, 1bit)  
	*aac_header_buff |= (0 << 1);																//layer (0, 2bits)  
	*aac_header_buff |= 1;																		//protection_absent (1, 1bit)  
	aac_header_buff++;  
	*aac_header_buff = (unsigned char)((1 & 0x3) << 6);											//profile (profile, 2bits)  
	*aac_header_buff |= ((imi_make_aac_header_sampling_frequency_index(frequency) & 0xf) << 2);	//sampling_frequency_index (sam_idx, 4bits)  
	*aac_header_buff |= (0 << 1);																//private_bit (0, 1bit)  
	*aac_header_buff |= ((channel & 0x4) >> 2);													//channel_configuration (channel, high_1bit)  
	aac_header_buff++;  
	*aac_header_buff = ((channel & 0x3) << 6);													//channel_configuration (channel, low_2bits)  
	*aac_header_buff |= (0 << 5);																//original/copy (0, 1bit)  
	*aac_header_buff |= (0 << 4);																//home  (0, 1bit);  
	*aac_header_buff |= (0 << 3);																//copyright_identification_bit (0, 1bit)  
	*aac_header_buff |= (0 << 2);																//copyright_identification_start (0, 1bit)  
	*aac_header_buff |= ((frame_len & 0x1800) >> 11);											//frame_length (value, high_2bits)  
	aac_header_buff++;  
	*aac_header_buff++ = (unsigned char) ((frame_len & 0x7f8) >> 3);							//frame_length (value, middle_8bits)  
	*aac_header_buff = (unsigned char) ((frame_len & 0x7) << 5);								//frame_length (value, low_3bits)  
	*aac_header_buff |= 0;																		//adts_buffer_fullness (0x7ff, high_5bits)  
	aac_header_buff++;  
	*aac_header_buff = 0;																		//adts_buffer_fullness (0x7ff, low_6bits)  
	*aac_header_buff |= 0;																		//number_of_raw_data_blocks_in_frame (0, 2bits);  
	aac_header_buff++;
	return aac_header;
}

inline unsigned char* imi_make_aac_track_configure(unsigned int profile, unsigned int sampling_frequency_index, unsigned int channel_configuration)
{
	typedef struct _aac_es_config
	{
		unsigned int _resv:3;
		unsigned int _channel:4;
		unsigned int _sample:4;
		unsigned int _type:5;
	}aac_es_config;

	unsigned char temp[2];
	unsigned char* trak = (unsigned char*)malloc(2);

	aac_es_config t = {0};
	t._type = profile;
	t._sample = sampling_frequency_index;
	t._channel = channel_configuration;
	t._resv = 0;

	memcpy(temp, &t, sizeof(temp));
	trak[0] = temp[1];
	trak[1] = temp[0];
	return trak;
}

#pragma pack(pop)

#endif